package com.airlines.crewassignment.service.optaplanner.impl;

import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.optaplanner.core.api.solver.Solver;
import org.optaplanner.core.api.solver.SolverFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.airlines.base.config.response.ResponseResult;
import com.airlines.crewassignment.constant.CrewConstant;
import com.airlines.crewassignment.domain.Crew;
import com.airlines.crewassignment.domain.CrewLinkLineRoster;
import com.airlines.crewassignment.domain.CrewLinkLineRosterGlobalValue;
import com.airlines.crewassignment.domain.CrewPositionAssignment;
import com.airlines.crewassignment.domain.DateTimeRange;
import com.airlines.crewassignment.domain.LinkLine;
import com.airlines.crewassignment.domain.Position;
import com.airlines.crewassignment.domain.rule.AssignmentRule;
import com.airlines.crewassignment.service.crew.CrewService;
import com.airlines.crewassignment.service.linkline.LinkLineService;
import com.airlines.crewassignment.service.linkline.PositionService;
import com.airlines.crewassignment.service.optaplanner.OptaplannerService;
import com.airlines.crewassignment.service.rule.AssignmentRuleService;
import com.airlines.crewassignment.service.ruleverification.RuleVerificationService;

/**
 * @author xxxx
 * @date 2018年3月28日 
 * @description
 */
@Service
public class OptaplannerServiceImpl implements OptaplannerService{
	@Autowired
	private CrewService crewService;
	@Autowired
	private LinkLineService linkLineService;
	@Autowired
	private PositionService positionService;
	@Autowired
	private AssignmentRuleService assignmentRuleService;
	@Autowired
	private RuleVerificationService ruleVerificationService;
	@Override
	public CrewLinkLineRoster crewLinkLineRosterInit(String dutyCode,DateTime start, DateTime end) {
		//1-1.初始化所有人以及排班用的经历信息
		List<Crew> crewList  = new ArrayList<>();
		List<Crew> crewListEveryDay  = crewService.listCrewAllInfo(dutyCode, start.toDate(),end.toDate());
		crewList.addAll(crewListEveryDay);
		
		
		//1-2.初始化所有的连线信息
		List<LinkLine> linkLineList = new ArrayList<>();
		for(DateTime temp = start; !temp.isAfter(end) ;temp = temp.plusDays(1)){
			List<LinkLine> linkLineListEveryDay = linkLineService.listLinkLineAllInfo(dutyCode,temp.toDate(),true);
			linkLineList.addAll(linkLineListEveryDay);
		}
		
		
		//1-3.上一次连线初始化
		for(LinkLine l: linkLineList){
			linkLineService.initLastLinkLine(l, start.toDate());
		}
		
		
		
		//2-1.CrewPositionAssignment 方案变量初数量初始化
		List<CrewPositionAssignment> crewPositionAssignmentList = new ArrayList<>();
		List<Position> positionList =  new ArrayList<>();
		for(LinkLine linkLine : linkLineList){
			List<Position> positionListEveryLinkLine = linkLine.getPositionList();
			for(Position p : positionListEveryLinkLine){
				p.setLinkLine(linkLine);
				
				CrewPositionAssignment c = new CrewPositionAssignment();
				c.setPosition(p);
				crewPositionAssignmentList.add(c);
				positionList.add(p);
			}
			
		}

		//2-2.全局变量定义
		CrewLinkLineRosterGlobalValue globalValue = new CrewLinkLineRosterGlobalValue();
		globalValue.setAssignmentDateRange(new DateTimeRange(start,end));
		
		//2-3.规则初始化
		List<AssignmentRule> assignmentRuleList = assignmentRuleService.listAll(dutyCode);
		
		//3.解决方案构造
		CrewLinkLineRoster crewLinkLineRosterUnsolver = new CrewLinkLineRoster();
		crewLinkLineRosterUnsolver.setLinkLineList(linkLineList);
		crewLinkLineRosterUnsolver.setCrewPositionAssignmentList(crewPositionAssignmentList);
		crewLinkLineRosterUnsolver.setCrewList(crewList);
		crewLinkLineRosterUnsolver.setPositionList(positionList);
		crewLinkLineRosterUnsolver.setAssignmentRuleList(assignmentRuleList);
		crewLinkLineRosterUnsolver.setCrewLinkLineRosterGlobalValue(globalValue);
		
		
		return crewLinkLineRosterUnsolver;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public HardSoftScore autoAssignF(DateTime start, DateTime end) {
		String dutyCode = CrewConstant.DUTY_F;
		//1-0.排班前，将所有的号位工号置为空
		for(DateTime temp = start; !temp.isAfter(end) ;temp = temp.plusDays(1)){
			positionService.updatePcodeNull(temp.toDate(),dutyCode);
		}
		
		//2.解决方案构造
		CrewLinkLineRoster crewLinkLineRosterUnsolver = this.crewLinkLineRosterInit(dutyCode,start, end);
			
		//4.自动排班	 
		SolverFactory<CrewLinkLineRoster> solverFactory = SolverFactory.createFromXmlResource("optaplanner/solver/crewLinkLineRosterSolverConfig.xml");
		Solver<CrewLinkLineRoster> solver = solverFactory.buildSolver();
		CrewLinkLineRoster crewLinkLineRosterSolver = solver.solve(crewLinkLineRosterUnsolver);
		

		//5.将排班结果保存到数据库,如果得分为负值，则不保存结果
		if(crewLinkLineRosterSolver.getScore().getHardScore()<=0){
			List<Position> positionSolverList = new ArrayList<>();
			for(CrewPositionAssignment c :crewLinkLineRosterSolver.getCrewPositionAssignmentList()){
				Position p  = c.getPosition();
				if(c.getCrew() != null){
					p.setWorkcode(c.getCrew().getWorkcode());
					p.setPCode(c.getCrew().getPCode());
				}
				positionSolverList.add(p);
				
			}
			positionService.saveAutoAssign(positionSolverList, dutyCode);
		}
		
		//6.将排班结果得分明细保存到数据库
		ruleVerificationService.checkAndSaveAssignmentF(start, end);
		return crewLinkLineRosterSolver.getScore();		
	}


	@Override
	public ResponseResult<String> autoAssignFCk(DateTime flightDateStart, DateTime flightDateEnd) {
		//1.排班前的所有连线，必须已经全部排班完毕，排班是顺序的，不允许先排后面的，再排前面的
		
		return null;
	}

	@Override
	public HardSoftScore autoAssignC(DateTime start, DateTime end) {
		String dutyCode = CrewConstant.DUTY_C;
		//1-0.排班前，将所有的号位工号置为空
		for(DateTime temp = start; !temp.isAfter(end) ;temp = temp.plusDays(1)){
			positionService.updatePcodeNull(temp.toDate(), dutyCode);
		}


		//2.解决方案构造
		CrewLinkLineRoster crewLinkLineRosterUnsolver = this.crewLinkLineRosterInit(dutyCode,start, end);
					
		//4.自动排班	 
		SolverFactory<CrewLinkLineRoster> solverFactory = SolverFactory.createFromXmlResource("optaplanner/solverC/solverConfig.xml");
		Solver<CrewLinkLineRoster> solver = solverFactory.buildSolver();
		CrewLinkLineRoster crewLinkLineRosterSolver = solver.solve(crewLinkLineRosterUnsolver);
				

		//5.将排班结果保存到数据库,如果得分为负值，则不保存结果
		if(crewLinkLineRosterSolver.getScore().getHardScore()<=0){
			List<Position> positionSolverList = new ArrayList<>();
			for(CrewPositionAssignment c :crewLinkLineRosterSolver.getCrewPositionAssignmentList()){
				Position p  = c.getPosition();
				if(c.getCrew() != null){
					p.setWorkcode(c.getCrew().getWorkcode());
					p.setPCode(c.getCrew().getPCode());
				}
				positionSolverList.add(p);
				
			}
			positionService.saveAutoAssign(positionSolverList,dutyCode);
		}
		
		//6.将排班结果得分明细保存到数据库
//				ruleVerificationService.checkAndSaveAssignmentF(start, end);
		return crewLinkLineRosterSolver.getScore();		
	}

	
		
}
